﻿//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Container;

namespace Syrinx
{
	public class BizObjDataScarfBizRules : BaseDataScarfBizRules
	{
		public void startBizObjListDataScarf(IApplication app, IRuleContext context, IBizObjList scarfInfos, string saveRuntimeLocation)
		{
			IRuleGroup rg = null;
			foreach (IBizObj scarfInfo in scarfInfos)
			{
				if (!Swaf.Cmn.IsEmpty(saveRuntimeLocation))
					scarfInfo.put("saveRuntimeLocation", Swaf.Cmn.pathCombine(saveRuntimeLocation, (string)scarfInfo.get("id") + ".xml"));
				object[] ruleParams = new object[] { scarfInfo };
				if (rg == null)
					rg = app.ruleMgr.executeAsync("startBizObjDataScarf", null, "", ruleParams);
				else
					rg.executeAsync("startBizObjDataScarf", null, "", ruleParams);
			}
			if (rg != null)
				rg.waitForCompletion(true);
		}

		public void startBizObjDataScarf(IApplication app, IRuleContext context, IBizObj scarfInfo)
		{
			string finalUrl;
			DateTime startTime = DateTime.Now;
			scarfInfo.put("runtime.startTime", startTime);

			if (!Cmn.IsEmpty(scarfInfo.get("preLogin.url")))
				getPageText((IBizObj)scarfInfo.get("preLogin"), scarfInfo, new NameAddressSupportDictionaryWrapper(scarfInfo), out finalUrl, null);

			if (!Cmn.IsEmpty(scarfInfo.get("login.url")))
			{
				string resp = loginUser(scarfInfo);
				if (!Cmn.IsEmpty(scarfInfo.get("loginFieldRegex")))
				{
					Regex loginFormRegex = new Regex((string)scarfInfo.get("loginFieldRegex"), RegexOptions.Singleline | RegexOptions.IgnoreCase);
					Match m = loginFormRegex.Match(resp);
					if (m.Success)
					{
						Hashtable t = new Hashtable();
						string[] gnames = loginFormRegex.GetGroupNames();
						foreach (string gname in gnames)
							if (gname.CompareTo("0") != 0)
								t[gname] = m.Groups[gname].Value;
						scarfInfo.put("login.data", app.resMgr.resolve((string)scarfInfo.get("login.data"), t));
					}
					loginUser(scarfInfo);
				}
			}
			if (!Cmn.IsEmpty(scarfInfo.get("postLogin.url")))
				getPageText((IBizObj)scarfInfo.get("postLogin"), scarfInfo, new NameAddressSupportDictionaryWrapper(scarfInfo), out finalUrl, null);

			string page = getPageText((IBizObj)scarfInfo.get("initialStart"), scarfInfo, new NameAddressSupportDictionaryWrapper(scarfInfo), out finalUrl, null);

			IBizObjList connectors = (IBizObjList)scarfInfo.get("connectors");
			IRuleGroup rg = null;
			foreach (IBizObj connector in connectors)
				callRule(app, scarfInfo, ref rg, "processConnectorDataScarf", page, finalUrl, null, connector, scarfInfo, 0, 1);
			if (rg != null)
				rg.waitForCompletion(true);

			if (!Cmn.IsEmpty(scarfInfo.get("logoutUrl")))
				getPageText(app.resMgr.resolve((string)scarfInfo.get("logoutUrl"), new NameAddressSupportDictionaryWrapper(scarfInfo)), scarfInfo);

			DateTime endTime = DateTime.Now;
			scarfInfo.put("runtime.endTime", endTime);

			string saveRuntime = (string)scarfInfo.get("saveRuntimeLocation");
			if (!Swaf.Cmn.IsEmpty(saveRuntime))
				System.IO.File.WriteAllText(app.resMgr.resolve(saveRuntime), ((IBizObj)scarfInfo.get("runtime")).Xml);
		}

		public void processConnectorDataScarf(IApplication app, IRuleContext context, string page, string pageUrl, IBizObj parent, IBizObj connector, IBizObj scarfInfo, int curDepth, int pageIndex)
		{
			int totalPages = -1;
			if (page != null)
			{
				totalPages = (int)connector.get("runtime.totalPages");
				//if (totalPages == -1)
				//{
					if (!Cmn.IsEmpty(connector.get("totalPagesRegex")))
					{
						Regex tgr = new Regex((string)connector.get("totalPagesRegex"), RegexOptions.Singleline | RegexOptions.IgnoreCase);
						Match m = tgr.Match(page);
						if (m.Success)
							connector.put("runtime.totalPages", totalPages = int.Parse(m.Groups["lastPage"].Value));
					}
					else
						connector.put("runtime.totalPages", totalPages = 1);
				//}
			}
			else
				totalPages = (int)connector.get("runtime.totalPages");

			if (page == null && pageIndex <= totalPages && !Cmn.IsEmpty(connector.get("specificListPage.url")))
			{
				FlexiMap m = new FlexiMap();
				m["pageIndex"] = pageIndex.ToString();
				m["parent"] = parent;
				DictionaryStack ds = new DictionaryStack(m, new NameAddressSupportDictionaryWrapper(connector), new NameAddressSupportDictionaryWrapper(scarfInfo));
				page = getPageText((IBizObj)connector.get("specificListPage"), scarfInfo, ds, out pageUrl, null);
			}

			if (page != null)
			{
				string connectorSection = page;
				if (!Cmn.IsEmpty(connector.get("sectionRegex")))
				{
					Regex sectionRe = new Regex((string)connector.get("sectionRegex"), RegexOptions.Singleline | RegexOptions.IgnoreCase);
					Match m2 = sectionRe.Match(page);
					if (m2.Success)
						connectorSection = m2.Groups[1].Value;
				}

				Regex conRe = new Regex((string)connector.get("elementRegex"), RegexOptions.Singleline | RegexOptions.IgnoreCase);
				MatchCollection mc = conRe.Matches(connectorSection);
				if (mc.Count > 0)
				{
					IRuleGroup rg = null;
					IBizObjList els = app.bizObjMgr.createList((string)connector.get("BizObjType"));
					foreach (Match m3 in mc)
					{
						IBizObj el = setupBizObj(scarfInfo, els.insertNew(), m3, conRe.GetGroupNames());

						if (!Cmn.IsEmpty(connector.get("getScript")))
						{
							object v = callScript(app, "getScript" + connector.get("id"), (string)connector.get("getScript"), scarfInfo, connector, el, parent);
							if (v != null)
							{
								el.isNew = false;
								if (Cmn.IsTrue(connector.get("useGetBizRuleAsKeyValue")))
									el.put(el.type.KeyFieldNames, v);
							}
						}
						else if (!Cmn.IsEmpty(connector.get("getDetailBizRule")))
						{
							object ruleParam = el.KeyValue;
							if (!Cmn.IsEmpty(connector.get("getBizRuleParamFieldName")))
								ruleParam = el.get((string)connector.get("getBizRuleParamFieldName"));
							IResults rc = app.ruleMgr.execute((string)connector.get("getDetailBizRule"), ruleParam);
							if (rc.CallResults != null)
							{
								el.isNew = false;
								if (Cmn.IsTrue(connector.get("useGetBizRuleAsKeyValue")))
									el.put(el.type.KeyFieldNames, rc.CallResults);
							}
						}

						if (el.isNew || (!el.isNew && (bool)connector.get("getDetailsWhenHaveAlready")))
							callRule(app, scarfInfo, ref rg, "processBizObjDataScarf", pageUrl, el, parent, connector, scarfInfo, curDepth + 1);
					}
				}
				if (pageIndex < totalPages)
				{
					IRuleGroup rg = null;
					callRule(app, scarfInfo, ref rg, "processConnectorDataScarf", null, null, parent, connector, scarfInfo, curDepth, pageIndex + 1);
				}
			}
		}

		protected object callScript(IApplication app, string name, string script, IBizObj scarfInfo, IBizObj connector, IBizObj obj, IBizObj parent)
		{
			object rc = null;
			Swaf.Script.ScriptManager scripts = ((Swaf.BizObj.BizObjManager)app.bizObjMgr).scripts;

			if (script != null && !scripts.isScriptFunctionDefined("jscript.NET", name))
				scripts.defineFunction("jscript.NET", name, new string[] { "app", "scarfInfo", "connector", "obj", "parent" }, script);

			rc = scripts.invokeScriptFunction("jscript.NET", name, new object[] { app, scarfInfo, connector, obj, parent });
			
			return rc;
		}

		protected IBizObj setupBizObj(IBizObj scarfInfo, IBizObj obj, Match m, string[] groupNames)
		{
			string[] fieldsToFilter = ((string)scarfInfo.get("filterFields")).Split(',');
			IBizObj filterInfo = (IBizObj)scarfInfo.get("filter");

			foreach (String gname in groupNames)
			{
				string val = m.Groups[gname].Value;
				if (val.Length != 0 && obj.containsField(gname))
				{
					foreach(string ff in fieldsToFilter)
						if (ff.CompareTo(gname) == 0)
						{
							val = Articles.ArticleContentFilteringBizRules.filterContent(App, val, filterInfo);
							break;
						}
					obj.put(gname, val);
				}
			}
			return obj;
		}

		protected object callRule(IApplication app, IBizObj scarfInfo, ref IRuleGroup rg, string ruleName, params object[] ruleParams)
		{
			object rc = null;
			if ((bool)scarfInfo.get("useParallel"))
				if (rg == null)
					rg = app.ruleMgr.executeAsync(ruleName, null, "", ruleParams);
				else
					rg.executeAsync(ruleName, null, "", ruleParams);
			else
				rc = app.ruleMgr.execute(ruleName, ruleParams);

			return (rc == null) ? rg : rc;
		}

		public void processBizObjDataScarf(IApplication app, IRuleContext context, string parentUrl, IBizObj obj, IBizObj parent, IBizObj connector, IBizObj scarfInfo, int curDepth)
		{
			string finalUrl = null;
			string page = null;
			if (!Cmn.IsEmpty(connector.get("elementDetails.url")))
			{
				DictionaryStack ds = new DictionaryStack(new NameAddressSupportDictionaryWrapper(obj), new NameAddressSupportDictionaryWrapper(scarfInfo));
				page = getPageText((IBizObj)connector.get("elementDetails"), scarfInfo, ds, out finalUrl, parentUrl);
			}

			if (obj.containsField("siteId"))
				obj.put("siteId", scarfInfo.get("id"));
			if (!Cmn.IsEmpty(connector.get("baseElementDetailRegex")))
			{
				Regex r = new Regex((string)connector.get("baseElementDetailRegex"), RegexOptions.Singleline | RegexOptions.IgnoreCase);
				Match m = r.Match(page);
				setupBizObj(scarfInfo, obj, m, r.GetGroupNames());
			}
			IBizObjList dataPoints = (IBizObjList)connector.get("dataPoints");
			foreach (IBizObj dataPoint in dataPoints)
				getDataPoint(app, context, scarfInfo, dataPoint, obj, parent, page);


			if (!Cmn.IsEmpty(connector.get("updateScript")))
				 callScript(app, "updateScript" + connector.get("id"), (string)connector.get("updateScript"), scarfInfo, connector, obj, parent);

			if (!Cmn.IsEmpty(connector.get("updateBizObjBizRule")))
				app.ruleMgr.execute((string)connector.get("updateBizObjBizRule"), obj);

			//Process connectors within this connector - this is spidering through links.
			IRuleGroup rg = null;
			IBizObjList connectors = (IBizObjList)connector.get("connectors");
			foreach (IBizObj childCon in connectors)
				callRule(app, scarfInfo, ref rg, "processConnectorDataScarf", page, finalUrl, obj, childCon, scarfInfo, curDepth+1, 1);
		}

		public void getDataPoint(IApplication app, IRuleContext context, IBizObj scarfInfo, IBizObj dataPoint, IBizObj obj, IBizObj parent, string page)
		{
			string finalUrl = null;
			if (!Cmn.IsEmpty(dataPoint.get("detail.url")))
			{
				DictionaryStack ds = new DictionaryStack(new NameAddressSupportDictionaryWrapper(obj), new NameAddressSupportDictionaryWrapper(scarfInfo));
				page = getPageText((IBizObj)dataPoint.get("detail"), scarfInfo, ds, out finalUrl, null);
			}

			if (!Cmn.IsEmpty(dataPoint.get("elementRegex")))
			{
				Regex detRe = new Regex((string)dataPoint.get("elementRegex"), RegexOptions.Singleline | RegexOptions.IgnoreCase);
				Match m = detRe.Match(page);
				if (m.Success)
					setupBizObj(scarfInfo, obj, m, detRe.GetGroupNames());
			}
			if (!Cmn.IsEmpty(dataPoint.get("value")))
			{
				FlexiMap m = new FlexiMap();
				m["parent"] = parent;
				DictionaryStack ds = new DictionaryStack(m, new NameAddressSupportDictionaryWrapper(obj), new NameAddressSupportDictionaryWrapper(scarfInfo));
				string val = (string)dataPoint.get("value");
				val = app.resMgr.resolve(val, ds);
				obj.put((string)dataPoint.get("fieldName"), val);

			}
		}


	}
}
